/*
    创建者：shuxiaokai
    创建时间：2021-09-26 21:41
    模块名称：将当前项目指定文档导出到其他项目
    备注：
*/
<template>
    <s-fieldset :title="$t('将当前项目指定文档导出到其他项目')" class="fork">
        <!-- 选择区域 -->
        <div class="fork-wrap">
            <div v-flex1="30" class="left">
                <span class="orange">
                    <span>{{ $t("从左侧拖拽文档到右侧，右侧也可以进行简单的拖拽") }}</span>
                </span>
                <el-divider></el-divider>
                <el-tree
                    ref="sourceTree"
                    class="mt-2"
                    :data="sourceTreeData"
                    node-key="_id"
                    draggable
                    :allow-drop="() => false"
                    :expand-on-click-node="true"
                    @node-drag-start="handleSourceDragstart"
                    @node-drag-over="handleSourceNodeDragOver"
                    @node-drag-end="handleSourceDragend"
                >
                    <template #default="scope">
                        <div class="custom-tree-node" tabindex="0">
                            <!-- file渲染 -->
                            <template v-if="!scope.data.isFolder">
                                <template v-for="(req) in projectInfo.rules.requestMethods">
                                    <span v-if="scope.data && scope.data.method && scope.data.method.toLowerCase() === req.value.toLowerCase()" :key="req.name" class="file-icon" :style="{color: req.iconColor}">{{ req.name }}</span>
                                </template>
                                <div class="node-label-wrap">
                                    <s-emphasize class="node-top" :title="scope.data.name" :value="scope.data.name"></s-emphasize>
                                </div>
                            </template>
                            <!-- 文件夹渲染 -->
                            <template v-if="scope.data.isFolder">
                                <i class="iconfont folder-icon iconweibiaoti-_huabanfuben"></i>
                                <div class="node-label-wrap">
                                    <s-emphasize class="node-top" :title="scope.data.name" :value="scope.data.name"></s-emphasize>
                                </div>
                            </template>
                        </div>
                    </template>
                </el-tree>
            </div>
            <div ref="target" v-flex1="30" class="right">
                <div>
                    <div class="orange">
                        <span>{{ $t("鼠标右键可以新增文件夹或者删除文件夹") }}</span>
                    </div>
                    <el-radio-group v-if="projectEnum.length < 4" v-model="targetProjectId" class="mt-2" @change="handleChangeProject">
                        <el-radio v-for="(item, index) in projectEnum" :key="index" :label="item._id">{{ item.projectName }}</el-radio>
                    </el-radio-group>
                    <el-select v-else v-model="targetProjectId" :size="config.renderConfig.layout.size" class="mt-2" filterable @change="handleChangeProject">
                        <el-option v-for="(item,index) in projectEnum" :key="index" :value="item._id" :label="item.projectName"></el-option>
                    </el-select>
                    <el-divider></el-divider>
                    <s-loading :loading="loading" class="project-nav mt-2">
                        <el-tree
                            ref="targetTree"
                            :data="targetTreeData"
                            node-key="_id"
                            draggable
                            :allow-drop="checkTargetCouldDrop"
                            :expand-on-click-node="true"
                            :empty-text="$t('暂无文档，请在项目中添加至少一个文档')"
                            @node-drag-over="handleTargetNodeOver"
                            @node-drag-start="handleTargetDragStart"
                            @node-drop="handleTargetDrop"
                            @node-expand="clearContextmenu"
                            @node-collapse="clearContextmenu"
                        >
                            <template #default="scope">
                                <div class="custom-tree-node" tabindex="0">
                                    <!-- file渲染 -->
                                    <template v-if="!scope.data.isFolder">
                                        <template v-for="(req) in projectInfo.rules.requestMethods">
                                            <span v-if="scope.data.method.toLowerCase() === req.value.toLowerCase()" :key="req.name" class="file-icon" :style="{color: req.iconColor}">{{ req.name }}</span>
                                        </template>
                                        <div class="node-label-wrap">
                                            <s-emphasize class="node-top" :title="scope.data.name" :value="scope.data.name"></s-emphasize>
                                        </div>
                                    </template>
                                    <!-- 文件夹渲染 -->
                                    <template v-if="scope.data.isFolder">
                                        <i class="iconfont folder-icon iconweibiaoti-_huabanfuben"></i>
                                        <div class="node-label-wrap">
                                            <s-emphasize class="node-top" :title="scope.data.name" :value="scope.data.name"></s-emphasize>
                                        </div>
                                    </template>
                                </div>
                            </template>
                        </el-tree>
                    </s-loading>
                </div>
            </div>
        </div>
        <!-- <s-add-folder-dialog v-if="dialogVisible" :visible.sync="dialogVisible" :project-id="projectId" :pid="targetAddFolderMountedId" @success="handleAddFileAndFolderCb"></s-add-folder-dialog> -->
    </s-fieldset>
</template>

<script lang="ts" setup>
import { ref, Ref, onMounted, computed, ComponentPublicInstance, nextTick } from "vue"
import { ElMessage } from "element-plus";
import type { ApidocBanner, ApidocProjectEnum, Response } from "@@/global"
import type TreeStore from "element-plus/lib/components/tree/src/model/tree-store"
import type { DropType } from "element-plus/lib/components/tree/src/tree.type"
import type Node from "element-plus/lib/components/tree/src/model/node"
import { store } from "@/store/index"
import { axios } from "@/api/api"
import { router } from "@/router/index"
import { findNextSiblingById, findParentById, findPreviousSiblingById, forEachForest, uuid } from "@/helper"
import { $t } from "@/i18n/i18n"
// import type { TreeComponentProps }  from "element-plus/lib/components/tree/src/tree.type"

type DragState = {
    dragState: {
        showDropIndicator: boolean,
        allowDrop: boolean,
        draggingNode: Node | null,
        dropNode: Node | null,
        dropType: "before" | "after" | "inner" | "none" | null,
    }
}
type TreeInstance = DragState & TreeStore & ComponentPublicInstance

/*
|--------------------------------------------------------------------------
| 全局参数，生命周期
|--------------------------------------------------------------------------
*/
//项目id
const projectId = router.currentRoute.value.query.id as string;
const projectInfo = computed(() => store.state["apidoc/baseInfo"])
/*
|--------------------------------------------------------------------------
| 项目列表信息
|--------------------------------------------------------------------------
*/
//目标树数据加载
const loading = ref(false);
//目标树数据
const targetTreeData: Ref<ApidocBanner[]> = ref([]);
//目标项目 项目id
const targetProjectId = ref("");
//根据id获取目标项目详情数据
const handleChangeProject = (pid: string | number | boolean) => {
    loading.value = true;
    const params = {
        projectId: pid,
    };
    axios.get("/api/project/doc_tree_node", { params }).then((res) => {
        targetTreeData.value = res.data;
    }).catch((err) => {
        console.error(err);
    }).finally(() => {
        loading.value = false;
    });
}
//项目列表枚举
const projectEnum: Ref<ApidocProjectEnum[]> = ref([]);
const getProjectEnum = () => {
    axios.get<Response<ApidocProjectEnum[]>, Response<ApidocProjectEnum[]>>("/api/project/project_enum").then((res) => {
        res.data.forEach((val) => {
            if (val._id !== projectId) { //过滤掉当前项目
                projectEnum.value.push(val);
            }
        })
        if (projectEnum.value.length > 0) {
            targetProjectId.value = projectEnum.value[0]._id;
            handleChangeProject(projectEnum.value[0]._id);
        }
    }).catch((err) => {
        console.error(err);
    });
}
onMounted(() => {
    getProjectEnum();
})

/*
|--------------------------------------------------------------------------
| 原树和目标树 基础数据
|--------------------------------------------------------------------------
|
*/
//目标数实例
const targetTree: Ref<(TreeInstance) | null> = ref(null);
//源树组件实例
const sourceTree: Ref<(TreeInstance) | null> = ref(null);

//源树数据
const sourceTreeData = computed(() => {
    const copyData: (ApidocBanner & { _isSource?: boolean })[] = JSON.parse(JSON.stringify(store.state["apidoc/banner"].banner));
    forEachForest(copyData, (data) => {
        data._isSource = true;
    });
    return copyData;
});
/*
|--------------------------------------------------------------------------
| 拖拽相关
|--------------------------------------------------------------------------
|
*/
//是否在源树中，如果在则取消拖拽到目标树事件
const isInSource = ref(false);
//判断目标树是否允许drop
const checkTargetCouldDrop = (draggingNode: Node, dropNode: Node, type: DropType) => {
    // let realDragNode = draggingNode || targetTree.value?.dragState.draggingNode
    // if (!realDragNode.data.isFolder && dropNode.data.isFolder && type !== "inner") { //不允许文件在文件夹前面
    //     return type !== "prev";
    // }
    // if (realDragNode.data.isFolder && !dropNode.data.isFolder) {
    //     return false;
    // }
    // if (!dropNode.data.isFolder) {
    //     return type !== "inner";
    // }
    console.log(type)
    return true;
}

//目标树dragStart
const handleTargetDragStart = (event: Event, node: Node) => {
    console.log("target start", node, event)
    isInSource.value = false;
}
//在目标树上拖拽
const handleTargetNodeOver = () => {
    console.log("target over")
    isInSource.value = false;
}
//排序目标树
const sortTargetTree = (node: Node, dropNode: Node, type: DropType) => {
    const params = {
        _id: node.data._id, //当前节点id
        pid: "", //父元素
        sort: 0, //当前节点排序效果
        projectId,
        dropInfo: {
            nodeName: node.data.name,
            nodeId: node.data._id,
            dropNodeName: dropNode.data.name,
            dropNodeId: dropNode.data._id,
            dropType: type,
        },
    };
    const pData = findParentById(targetTreeData.value, node.data._id, { idKey: "_id" });
    params.pid = pData ? pData._id : "";
    if (type === "inner") {
        params.sort = Date.now();
    } else {
        const nextSibling = findNextSiblingById(targetTreeData.value, node.data._id, { idKey: "_id" }) || { sort: 0 };
        const previousSibling = findPreviousSiblingById(targetTreeData.value, node.data._id, { idKey: "_id" }) || { sort: 0 };
        const previousSiblingSort = previousSibling.sort || 0;
        const nextSiblingSort = nextSibling.sort || Date.now();
        params.sort = (nextSiblingSort + previousSiblingSort) / 2;
        node.data.sort = (nextSiblingSort + previousSiblingSort) / 2;
    }
    axios.put("/api/project/change_doc_pos", params).catch((err) => {
        console.error(err)
    });
}
//目标树drop
const handleTargetDrop = (dragNode: Node, dropNode: Node, type: DropType) => {
    console.log("drop111")
    if (isInSource.value) { //拖拽到目标节点又拖拽回源节点代表取消
        targetTree.value?.remove(dragNode.data);
        return;
    }
    let targetNodeSort = Date.now();
    const { _isSource } = dragNode.data;
    if (_isSource) { //从源树拖拽到目标树
        let targetMountedId = null;
        const dropNodeId = dropNode.data._id2 || dropNode.data._id;
        const dragNodeId = dragNode.data._id2 || dragNode.data._id;
        if (type === "inner") { //拖放至内部则选择dropNode
            targetMountedId = dropNodeId;
        } else {
            const dropNodeParentNode = findParentById(targetTreeData.value, dropNodeId, { idKey: "_id" });
            const nextSibling = findNextSiblingById(targetTreeData.value, dragNodeId, { idKey: "_id" }) || { sort: 0 };
            const previousSibling = findPreviousSiblingById(targetTreeData.value, dragNodeId, { idKey: "_id" }) || { sort: 0 };
            const previousSiblingSort = previousSibling.sort || 0;
            const nextSiblingSort = nextSibling.sort || Date.now();
            targetNodeSort = (nextSiblingSort + previousSiblingSort) / 2;
            dropNode.data.sort = (nextSiblingSort + previousSiblingSort) / 2;
            if (dropNodeParentNode) { //非根节点
                targetMountedId = dropNodeParentNode._id;
            }
        }
        const selectedDocIds: string[] = [];
        forEachForest([dragNode.data], (data) => {
            selectedDocIds.push(data._id2 || data._id);
        });
        const params = {
            sourceRootId: dragNode.data._id2 || dragNode.data._id, //源节点根id
            selectedDocIds, //需要挂载的节点ids
            sourceProjectId: projectId, //源项目id
            targetProjectId: targetProjectId.value, //目标项目id
            targetMountedId, //目标挂载节点id
            targetNodeSort,
        };
        axios.post("/api/project/export/fork", params).then((res) => {
            const docsIdMap = res.data;
            forEachForest(targetTreeData.value, (data) => {
                const { _id } = data;
                const newId = docsIdMap[_id]
                if (newId) {
                    data._id = newId;
                }
            });
            ElMessage.success($t("导入成功"));
        }).catch((err) => {
            console.error(err);
        });
    } else { //目标树内自己拖拽，调用排序而不是新增
        // console.log("目标树内自己拖拽")
        sortTargetTree(dragNode, dropNode, type);
    }
    dragNode.data._isSource = false;
}

//拖拽开始(源)
const handleSourceDragstart = (node: Node, event: Event) => {
    console.log("drag start", targetTree.value, event, node)
    if (targetTree.value) {
        // targetTree.value.dragState.draggingNode = { node };
    }
}
//拖拽中(源)
const handleSourceNodeDragOver = () => {
    isInSource.value = true;
}
//拖拽完毕(源)
const handleSourceDragend = (draggingNode: Node, dropNode: Node, position: unknown, event: DragEvent) => {
    // 插入一个空节点用于占位
    const emptyData = {
        _id: uuid(),
    };
    sourceTree.value?.insertBefore(emptyData, draggingNode);
    targetTree.value?.$emit("node-drag-end", event);
    nextTick(() => {
        if (sourceTree.value?.getNode(draggingNode.data)) { //没有在挂载点完成拖拽
            sourceTree.value?.remove(emptyData);
        } else { //在挂载点完成拖拽
            const data = JSON.parse(JSON.stringify(draggingNode.data));
            data._id2 = data._id2 || data._id;
            data._id = uuid();
            data._isSource = true; //当前节点还原为source
            sourceTree.value?.insertAfter(data, sourceTree.value?.getNode(emptyData));
            sourceTree.value?.remove(emptyData);
        }
    })
    // console.log(event, sourceTree.value, nextTick)
}

//清除contentmenu
const clearContextmenu = () => {
    // console.log(333)
}

</script>

<style lang="scss">
.fork {
    .el-divider--horizontal {
        margin: size(10) 0;
    }
    .fork-wrap {
        display: flex;
        .left {
            flex: 0 0 50%;
            border-right: 1px solid $gray-300;
        }
        .right {
            flex: 1;
            padding: 0 size(15);
        }
        .el-tree-node__content {
            height: size(30);
            display: flex;
            align-items: center;
        }
        .custom-tree-node {
           display: flex;
            align-items: center;
            width: 100%;
            overflow: hidden;
            height: size(30);
            &:hover {
                .more {
                    display: block;
                }
            }
            .file-icon {
                font-size: fz(14);
                margin-right: size(5);
            }
            .folder-icon {
                color: $yellow;
                flex: 0 0 auto;
                width: size(16);
                height: size(16);
                margin-right: size(5);
            }
            .node-label-wrap {
                display: flex;
                flex-direction: column;
                flex: 1;
                overflow: hidden;
                .node-top {
                    width: 100%;
                    overflow: hidden;
                    text-overflow: ellipsis;
                    white-space: nowrap;
                }
                .node-bottom {
                    color: $gray-500;
                    width: 100%;
                    overflow: hidden;
                    text-overflow: ellipsis;
                    white-space: nowrap;
                }
            }
        }
    }
    //拖拽指示器样式
    .el-tree-node.is-drop-inner {
        background: mix($theme-color, $white, 70%);
        .custom-tree-node.select-node {
            background-color: mix($theme-color, $white, 70%);
        }
    }
    .el-tree__drop-indicator {
        height: size(3);
    }
}
</style>
